/**
 * @file   Int64.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2014-04-19
 * @brief  DON data type object: Int64
 *
 * Copyright 2014  Djuro Drljaca (djurodrljaca@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DON/Core/DataType/Int64.h>
#include <DON/Core/Platform/PlatformDefines.h>
#include <QtCore/QByteArray>

using namespace DON::Core::DataType;

class Int64::Private
{
public:
    Private()
        : value(0ll)
    { }

    qint64 value;
};

Int64::Int64()
    : AbstractDataType(),
      d(new Private())
{
}

Int64::Int64(const Int64 &other)
    : AbstractDataType(),
      d(new Private())
{
    d->value = other.d->value;
}

Int64::~Int64()
{
    delete d;
}

Int64 & Int64::operator=(const Int64 &other)
{
    d->value = other.d->value;

    return *this;
}

AbstractDataType * Int64::clone() const
{
    return new Int64(*this);
}

DataType Int64::getDataType() const
{
    return DataType_Int64;
}

qint64 Int64::getValue() const
{
    return d->value;
}

void Int64::setValue(const qint64 value)
{
    d->value = value;
}

bool Int64::fromBinary(const QByteArray &data, const int startIndex, int *size)
{
    bool success = false;
    qint64 value = Int64::fromBinary(data, startIndex, &success);

    if (success)
    {
        d->value = value;

        if (size != NULL)
        {
            *size = 8;
        }
    }

    return success;
}

QByteArray Int64::toBinary() const
{
    return Int64::toBinary(d->value);
}

Int64 * Int64::fromAbstractDataType(AbstractDataType *instance)
{
    Int64 *outputInstance = NULL;

    if (instance != NULL)
    {
        if (instance->getDataType() == DataType_Int64)
        {
            outputInstance = static_cast<Int64 *>(instance);
        }
    }

    return outputInstance;
}

qint64 Int64::fromBinary(const QByteArray &data, const int startIndex, bool *ok)
{
    // TODO: add platform support!

    qint64 value = 0;
    bool success = false;

    if ((data.size() > 0) &&
        (startIndex >= 0) &&
        ((startIndex + 8) <= data.size()))
    {
#if (DON_CORE_PLATFORM_ENDIANESS_INTEGER == DON_CORE_PLATFORM_LITTLE_ENDIAN)
        value = static_cast<qint64>(data.at(startIndex)) |
                (static_cast<qint64>(data.at(startIndex + 1)) << 8) |
                (static_cast<qint64>(data.at(startIndex + 2)) << 16) |
                (static_cast<qint64>(data.at(startIndex + 3)) << 24) |
                (static_cast<qint64>(data.at(startIndex + 4)) << 32) |
                (static_cast<qint64>(data.at(startIndex + 5)) << 40) |
                (static_cast<qint64>(data.at(startIndex + 6)) << 48) |
                (static_cast<qint64>(data.at(startIndex + 7)) << 56);
#elif (DON_CORE_PLATFORM_ENDIANESS_FLOAT32 == DON_CORE_PLATFORM_BIG_ENDIAN)
        value = (static_cast<qint64>(data.at(startIndex)) << 56) |
                (static_cast<qint64>(data.at(startIndex + 1)) << 48) |
                (static_cast<qint64>(data.at(startIndex + 2)) << 40) |
                (static_cast<qint64>(data.at(startIndex + 3)) << 32) |
                (static_cast<qint64>(data.at(startIndex + 4)) << 24) |
                (static_cast<qint64>(data.at(startIndex + 5)) << 16) |
                (static_cast<qint64>(data.at(startIndex + 6)) << 8) |
                static_cast<qint64>(data.at(startIndex + 7));
#else
#  error "Unknown INTEGER endianess!"
#endif
    }

    if (ok != NULL)
    {
        *ok = success;
    }

    return value;
}

QByteArray Int64::toBinary(const qint64 value)
{
    QByteArray data;

#if (DON_CORE_PLATFORM_ENDIANESS_INTEGER == DON_CORE_PLATFORM_LITTLE_ENDIAN)
    data.append(static_cast<char>(value));
    data.append(static_cast<char>(value >> 8));
    data.append(static_cast<char>(value >> 16));
    data.append(static_cast<char>(value >> 24));
    data.append(static_cast<char>(value >> 32));
    data.append(static_cast<char>(value >> 40));
    data.append(static_cast<char>(value >> 48));
    data.append(static_cast<char>(value >> 56));
#elif (DON_CORE_PLATFORM_ENDIANESS_FLOAT32 == DON_CORE_PLATFORM_BIG_ENDIAN)
    data.append(static_cast<char>(value >> 56));
    data.append(static_cast<char>(value >> 48));
    data.append(static_cast<char>(value >> 40));
    data.append(static_cast<char>(value >> 32));
    data.append(static_cast<char>(value >> 24));
    data.append(static_cast<char>(value >> 16));
    data.append(static_cast<char>(value >> 8));
    data.append(static_cast<char>(value));
#else
#  error "Unknown INTEGER endianess!"
#endif

    return data;
}
